home *** CD-ROM | disk | FTP | other *** search
/ Delphi Informant Complete 1995 - 2000 / Delphi Informant Complete 1995 to 2000.iso / Delphi Informant Magazine Complete Works SOURCE CODE 1998.rar / 1998 / Sep / di9809am / Compont / TAPIcomp.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1998-06-27  |  38.5 KB  |  1,026 lines

  1. {+--------------------------------------------------------------------------+
  2.  | Component:   TkkamTAPI
  3.  | Created:     6/3/98 6:35:50 PM
  4.  | Author:      Alan Moore and Ken Kyler
  5.  |              developed for article in Delphi Informant; September 1998
  6.  | Copyright    1998, all rights reserved.
  7.  | Description: TAPI non-visual component for basic Telephony functionality
  8.  | Version:     1.2
  9.  | Modification History:  Modifications by Ken Kyler and Alan Moore
  10.  +--------------------------------------------------------------------------+}
  11. unit TAPIcomp;  { TkkamTAPI component. }
  12. { Created 6/3/98 6:35:51 PM }
  13. { Eagle Software CDK, Version 3.02 Rev. F }
  14. { Version 1.1 completed 6/25/98 }
  15. { Version 1.2 completed 6/27/98 }
  16.  
  17. interface
  18.  
  19. uses
  20.   Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms,
  21.   Dialogs, Tapi, Menus, StdCtrls, ExtCtrls;
  22.  
  23. type
  24.   // Thread Action Type
  25.   TThreadAction = (taSuspend, taResume, taTerminate);
  26.  
  27.   // Comm Event Type
  28.   TCommEvent = (tceDSR, tceDTR, tceCTS, tcePORT);
  29.  
  30.   // Event Types
  31.   TTapiUpdateEvent = procedure(sender : TObject; UpdateList : TStringList)
  32.      of object;
  33.   TCommThreadEvent = procedure(sender : TObject; ThreadAction : TThreadAction)
  34.      of object;
  35.   TCommEventProc = procedure (sender : TObject; ACommEvent : TCommEvent;
  36.                           AStatus : integer) of object;
  37.  
  38.   // Our Thread Class moved from separate unit
  39.   type
  40.   TCommStatus = class(TThread)
  41.   private
  42.     { Private declarations }
  43.     ThePort : THandle;
  44.     function GetPort : THandle;
  45.     procedure SetPort(Value : THandle);
  46.   protected
  47.     TheOwner: TComponent;
  48.     property APort : THandle
  49.       read  GetPort
  50.       Write SetPort;
  51.       procedure Execute; override;
  52.       procedure TriggerTapiCommEvent(Sender : TObject;
  53.                           CommEvent : TCommEvent; Status : integer);
  54.     public
  55.       constructor Init(Owner : TComponent; Suspended : Boolean;
  56.                         PortRead : THandle);
  57.   end;
  58.  
  59.   // constants for thread and modem lights
  60.   const
  61.   off = 0;
  62.   red = 1;
  63.   yellow = 2;
  64.   green = 3;
  65.  
  66. type
  67.   // Main TAPI Class
  68.   TkkamTAPI = class(TComponent)
  69.   private
  70.     FAnswerCalls: Boolean;
  71.     FPulseDialing: boolean;
  72.     FCountryCode: integer;
  73.     FVersion: integer;
  74.     { Private declarations }
  75.     FLineCallParams: TLineCallParams;
  76.     FLineTranslateOptions: DWord;
  77.     FExt: TLINEEXTENSIONID;
  78.     FlpTranslateOutput: LPLINETRANSLATEOUTPUT;
  79.     FPort: THandle;
  80.     FTAPI_Initialized: Boolean;
  81.     FAutoSelectLine: Boolean;
  82.     FDev: Integer;
  83.     FPhoneNumber: String;
  84.     FMediaMode: DWord;
  85.     FBearerMode: DWord;
  86.     FLineIsOpen: Boolean;
  87.     FAnswserCalls : boolean;
  88.     FOnCreateCallManager: TTapiUpdateEvent;
  89.     FOnShutdownManager: TTapiUpdateEvent;
  90.     FOnDestroyCallManager : TTapiUpdateEvent;
  91.     FOnFreeCallManager: TTapiUpdateEvent;
  92.     FOnEnumerateDevices: TTapiUpdateEvent;
  93.     FOnOpenLine: TTapiUpdateEvent;
  94.     FOnDial: TTapiUpdateEvent;
  95.     FOnCommThreadEvent: TCommThreadEvent;
  96.     FOnTriggerCommEvent: TCommEventProc;
  97.     FOnTAPIInit: TNotifyEvent;  { Defined in Classes unit. }
  98.     // The next three events will usually not need to be used but are included
  99.     // in case you want to take additional steps after these changes occur.
  100.     // Generally, you should communicate from the calling application to this
  101.     // component to effect each of these changes
  102.     FOnPhoneNumberChange: TNotifyEvent;  { Defined in Classes unit. }
  103.     FOnChangeMediaMode: TNotifyEvent;  { Defined in Classes unit. }
  104.     FOnChangeBearerMode: TNotifyEvent;  { Defined in Classes unit. }
  105.     function ReadPhoneNumber :  string;
  106.     procedure WritePhoneNumber(NewPhoneNumber : String);
  107.    protected
  108.     { Protected declarations }
  109.     InitResults : TStringList;
  110.     DeviceList: TStringList;
  111.     ShutdownResults: TStringList;
  112.     CreateManagerResults : TStringList;
  113.     DialResults: TStringList;
  114.     { Event triggers: }
  115.     procedure TriggerCreateCallManagerEvent; virtual;
  116.     procedure TriggerShutdownManagerEvent; virtual;
  117.     procedure TriggerDestroyCallManagerEvent; virtual;
  118.     procedure TriggerEnumerateDevicesEvent; virtual;
  119.     procedure TriggerTAPIInitEvent; virtual;
  120.     procedure TriggerOpenLineEvent; virtual;
  121.     procedure TriggerDialEvent; virtual;
  122.     procedure TriggerPhoneNumberChangeEvent; virtual;
  123.     procedure TriggerChangeMediaModeEvent; virtual;
  124.     procedure TriggerChangeBearerModeEvent; virtual;
  125.     procedure TriggerCommThreadEvent(ThreadAction : TThreadAction); virtual;
  126.     procedure TriggerCommEvent(Sender : TObject;
  127.                                ACommEvent : TCommEvent; AStatus : integer);
  128.   public
  129.     { Public declarations }
  130.     CommStatusThread : TCommStatus;
  131.     constructor Create(AOwner: TComponent); override;
  132.     destructor Destroy; override;
  133.     function TapiInitialize: Boolean;
  134.     procedure EnumerateDevices;
  135.     function ShutdownManager: Boolean;
  136.     function CreateCallManager: Boolean;
  137.     function CheckLineIsOpen: boolean;
  138.     procedure ChangePhoneNumber(NewPhoneNumber : string);
  139.     function Dial: String;
  140.     procedure ChangeMediaMode(MediaModeSelected : Integer);
  141.     procedure ChangeBearerMode(BearerModeSelected : Integer);
  142.     procedure ShowLineTranslateDialog(APhoneNum : string; AHandle :  THandle);
  143.     function OpenLine(AcceptCalls : boolean; var OpenMsg : string): boolean;
  144.     property APort : THandle read FPort Write FPort;
  145.     // Use a MaskEdit on main form to enter phone number with the following
  146.     // edit mask:  !9 \(999\) 000-0000;1;_
  147.     property PhoneNumber: String read ReadPhoneNumber write WritePhoneNumber;
  148.     property TAPI_Initialized: Boolean read FTAPI_Initialized write
  149.              FTAPI_Initialized;
  150.     property MediaMode: DWord read FMediaMode write FMediaMode;
  151.     property Dev: Integer read FDev write FDev;  { Public }
  152.     property LineIsOpen : boolean read FLineIsOpen Write FLineIsOpen;
  153.   published
  154.     { Published properties and events }
  155.     property AutoSelectLine: Boolean read FAutoSelectLine write FAutoSelectLine
  156.              default true;
  157.     property AnswerCalls : boolean read FAnswerCalls Write FAnswerCalls;
  158.     property PulseDialing : boolean read FPulseDialing Write FPulseDialing;
  159.     property OnCreateCallManager: TTapiUpdateEvent read FOnCreateCallManager write
  160.              FOnCreateCallManager;
  161.     property OnShutdownManager: TTapiUpdateEvent read FOnShutdownManager
  162.              write FOnShutdownManager;
  163.     property OnDestroyCallManager: TTapiUpdateEvent read FOnDestroyCallManager
  164.              write FOnDestroyCallManager;
  165.     property OnEnumerateDevices: TTapiUpdateEvent read FOnEnumerateDevices
  166.              write FOnEnumerateDevices;
  167.     property OnTriggerCommEvent : TCommEventProc read FOnTriggerCommEvent
  168.              Write FOnTriggerCommEvent;
  169.     property OnTAPIInit: TNotifyEvent read FOnTAPIInit write FOnTAPIInit;
  170.     property OnOpenLine: TTapiUpdateEvent read FOnOpenLine write FOnOpenLine;
  171.     property OnDial: TTapiUpdateEvent read FOnDial write FOnDial;
  172.     property OnPhoneNumberChange: TNotifyEvent read FOnPhoneNumberChange
  173.              write FOnPhoneNumberChange;
  174.     property OnChangeMediaMode: TNotifyEvent read FOnChangeMediaMode
  175.              write FOnChangeMediaMode;
  176.     property OnChangeBearerMode: TNotifyEvent read FOnChangeBearerMode
  177.              write FOnChangeBearerMode;
  178.     property OnCommThreadEvent : TCommThreadEvent read FOnCommThreadEvent
  179.              Write FOnCommThreadEvent;
  180.   end;  { TkkamTAPI }
  181.  
  182.   var
  183.     LineApp: HLINEAPP;
  184.  
  185. procedure Register;
  186.  
  187. implementation
  188.  
  189. const
  190.   Ver = $00010004;  // API version accepted (1.4) [Windows 95]
  191.  
  192. // Local Variables -------------------------------------------------------------
  193. var
  194.   TapiMessages : TStringList; // local string list for TAPI results
  195.   Devices : TStringList;      // local string list for available devices
  196.   AkkamTAPI : TkkamTAPI;  // local copy of the TAPI component
  197.   LocalNumDevs : Integer;  // local copy of number of devices
  198.   ALineIsOpen : boolean;   // local copy of line open status
  199.   ALine : HLine; // local copy of line
  200.   ACall : HCall; // local copy of call
  201.   APhoneNumber : string; // local copy of phone number
  202. // Local Functions -------------------------------------------------------------
  203.  
  204. function RecordGetStr (var Data; Field : Pointer) : string;
  205. var
  206.   Len: Longint;
  207. begin
  208.   Len := PInt(Field)^; // PInt is defined in Windows.pas
  209.   Inc(PInt(Field));
  210.   if (PInt(Field)^ <> 0) then
  211.      SetString(Result, PChar(Longint(@Data) + PInt(Field)^), Len - 1)
  212.   else
  213.      Result:='';
  214. end;
  215.  
  216. function ShutdownCallManager(var ShutdownResults : string)
  217.            : boolean;
  218. var
  219.   S: string;
  220. begin
  221.   Result := false;
  222.   { LineShutDown performs the equivalent of LineClose
  223.     so set the line flag to false }
  224.   case LineShutdown(LineApp) of
  225.      0: begin
  226.         S := 'success!';
  227.         result := True;
  228.         ALineIsOpen := False;
  229.         AkkamTAPI.LineIsOpen := False;
  230.      end;
  231.      LINEERR_INVALAPPHANDLE: S := 'LINEERR_INVALAPPHANDLE';
  232.      LINEERR_NOMEM: S := 'LINEERR_NOMEM';
  233.      LINEERR_UNINITIALIZED: S := 'LINEERR_UNINITIALIZED';
  234.      LINEERR_RESOURCEUNAVAIL: S := 'LINEERR_RESOURCEUNAVAIL';
  235.   else
  236.      S := 'Unknown value';
  237.   end;
  238.   ShutdownResults := 'LineShutDown reports: ' + S;
  239.   AkkamTAPI.TriggerShutdownManagerEvent;
  240. end;
  241.  
  242.  
  243. procedure LineCallBack(hDevice, dwMessage, dwInstance, dwParam1,
  244.   dwParam2, dwParam3 : DWORD); stdcall; // handles messages from the line
  245. var
  246.   CallResults : string;
  247. begin
  248.   AkkamTAPI.DialResults.Clear;
  249.   with AkkamTAPI.DialResults do begin // Write TAPI results to string list for use
  250.                              // by Delphi components in TAPIForm unit
  251.     case dwMessage of
  252.       LINE_CALLSTATE: begin //reports asynchronous responses
  253.         case dwParam1 of
  254.            LINECALLSTATE_IDLE:
  255.               begin
  256.               Add('LCB (LINE_CALLSTATE): ' +
  257.                   'The call is idle - no call actually exists.');
  258.               If ShutdownCallManager(CallResults) then
  259.                  begin
  260.                  AkkamTAPI.TriggerShutdownManagerEvent;
  261.                    //Send TapiMessages to calling app
  262.                  AkkamTAPI.LineIsOpen := False;
  263.                  ALineIsOpen := False;
  264.                  end;
  265.               end;
  266.            LINECALLSTATE_OFFERING:
  267.                begin
  268.                  Add('LCB (LINE_CALLSTATE): ' +
  269.                    'The call is being offered to the station.');
  270.                  if dwParam3<>LINECALLPRIVILEGE_OWNER then
  271.                  Add('Cannot accept call because we don''t '+
  272.                       'have owner priviledges .')
  273.                  else
  274.                     begin
  275.                       Add('Attempting to accept incoming call');
  276.                       lineAccept(ACall, Nil, 0);
  277.                     end;
  278.               end;
  279.            LINECALLSTATE_ACCEPTED:
  280.               begin
  281.               Add('LCB (LINE_CALLSTATE): ' +
  282.                 'The call was offering and has been accepted.');
  283.               if MessageDlg('Do you want to accept this call?',
  284.                  mtConfirmation, [mbYes, mbNo], 0) = mrYes  then
  285.                  lineAnswer(ACall, Nil, 0);
  286.               end;
  287.            LINECALLSTATE_DIALTONE:
  288.               Add('LCB (LINE_CALLSTATE): The call is receiving a dial tone.');
  289.            LINECALLSTATE_DIALING:
  290.               Add('LCB (LINE_CALLSTATE): Dialing ' + APhoneNumber);
  291.            LINECALLSTATE_RINGBACK:
  292.               Add('LCB (LINE_CALLSTATE): The call is receiving ringback.');
  293.            LINECALLSTATE_BUSY: begin // note, difficult to detect
  294.            AkkamTAPI.TriggerCommEvent(Nil, tcePORT, red);
  295.              case dwParam2 of
  296.                LINEBUSYMODE_STATION:
  297.                  Add('LCB (LINE_CALLSTATE): ' +
  298.                      'Busy signal; called party''s station is busy.');
  299.                LINEBUSYMODE_TRUNK:
  300.                  Add('LCB (LINE_CALLSTATE): ' +
  301.                      'Busy signal; trunk or circuit is busy.');
  302.                LINEBUSYMODE_UNKNOWN:
  303.                  Add('LCB (LINE_CALLSTATE): ' +
  304.                      'Busy signal; specific mode is currently unkown');
  305.                LINEBUSYMODE_UNAVAIL:
  306.                  Add('LCB (LINE_CALLSTATE): ' +
  307.                      'Busy signal; specific mode is unavailable');
  308.              else
  309.                Add('LCB (LINE_CALLSTATE): ' +
  310.                    'The call is receiving an unidentifiable busy tone.');
  311.              end;
  312.              ShutdownCallManager(CallResults);
  313.              AkkamTAPI.TriggerShutdownManagerEvent;
  314.                // Send TapiMessages to calling app
  315.              AkkamTAPI.TriggerCommEvent(Nil, tcePORT, green);
  316.            end;
  317.            LINECALLSTATE_SPECIALINFO:
  318.               Add('LCB (LINE_CALLSTATE): ' +
  319.                   'Special information is sent by the network.');
  320.            LINECALLSTATE_CONNECTED:
  321.               Add('LCB (LINE_CALLSTATE): ' +
  322.                   'The call has been established and the connection is made.');
  323.            LINECALLSTATE_PROCEEDING:
  324.               Add('LCB (LINE_CALLSTATE): ' +
  325.                   'Dialing has completed and the call is proceeding.');
  326.            LINECALLSTATE_ONHOLD:
  327.               Add('LCB (LINE_CALLSTATE): The call is on hold by the switch.');
  328.            LINECALLSTATE_CONFERENCED:
  329.               Add('LCB (LINE_CALLSTATE): The call is ' +
  330.                   'currently a member of a multi-party conference call.');
  331.            LINECALLSTATE_ONHOLDPENDCONF:
  332.               Add('LCB (LINE_CALLSTATE): The call is currently ' +
  333.                   'on hold while it is being added to a conference.');
  334.            LINECALLSTATE_DISCONNECTED: begin
  335.               Add('LCB (LINE_CALLSTATE): The line has been disconnected.');
  336.               case dwParam2 of
  337.                 LINEDISCONNECTMODE_NORMAL:
  338.                    Add(#9 + 'This is a "normal" disconnect request.');
  339.                 LINEDISCONNECTMODE_UNKNOWN:
  340.                    Add(#9+'The reason for the disconnect request is unknown.');
  341.                 LINEDISCONNECTMODE_REJECT:
  342.                    Add(#9 + 'The remote user has rejected the call.');
  343.                 LINEDISCONNECTMODE_PICKUP:
  344.                    Add(#9 + 'The call was picked up from elsewhere.');
  345.                 LINEDISCONNECTMODE_FORWARDED:
  346.                    Add(#9 + 'The call was forwarded by the switch.');
  347.                 LINEDISCONNECTMODE_BUSY:
  348.                    Add(#9 + 'The remote user''s station is busy.');
  349.                 LINEDISCONNECTMODE_NOANSWER:
  350.                    Add(#9 + 'The remote user''s station does not answer.');
  351.                 LINEDISCONNECTMODE_BADADDRESS:
  352.                    Add(#9 + 'The destination address in invalid.');
  353.                 LINEDISCONNECTMODE_UNREACHABLE:
  354.                    Add(#9 + 'The remote user could not be reached.');
  355.                 LINEDISCONNECTMODE_CONGESTION:
  356.                    Add(#9 + 'The network is congested.');
  357.                 LINEDISCONNECTMODE_INCOMPATIBLE: Add(#9 +
  358.                    'The remote user''s station equipment is incompatible');
  359.                 LINEDISCONNECTMODE_UNAVAIL:
  360.                    Add(#9 + 'The reason for the disconnect is unavailable');
  361.               end;
  362.            end;
  363.            LINECALLSTATE_UNKNOWN:
  364.               Add('LCB (LINE_CALLSTATE): The state of the call is not known.');
  365.            end;
  366.         end;
  367.       LINE_LINEDEVSTATE:
  368.         case dwParam1 of // incomplete list
  369.            LINEDEVSTATE_RINGING:
  370.               Add('LCB (LINE_LINEDEVSTATE): (Ringing) Ring, ring, ring...');
  371.            LINEDEVSTATE_CONNECTED:
  372.               Add('LCB (LINE_LINEDEVSTATE): Connected...');
  373.            LINEDEVSTATE_DISCONNECTED:
  374.               Add('LCB (LINE_LINEDEVSTATE): Disconnected.');
  375.            LINEDEVSTATE_REINIT: // line device has changed or been modified
  376.               if (dwParam2 = 0) then begin
  377.                  Add('LCB (LINE_LINEDEVSTATE): Shutdown required');
  378.                  ShutdownCallManager(CallResults);
  379.                    // Send TapiMessages to calling app
  380.               end;
  381.         end;
  382.       LINE_REPLY:
  383.         if (dwParam2 = 0) then
  384.            Add('LCB (LINE_REPLY): LineMakeCall completed successfully')
  385.         else
  386.            Add('LCB (LINE_REPLY): LineMakeCall failed');
  387.     end;
  388.   end;
  389.   AkkamTAPI.TriggerDialEvent;
  390. end;
  391.  
  392. function GetPortHandle : THandle;
  393. { code courtesy of Keith Anderson, Keith@PureScience.com
  394.   This code returns the port handle required to pass to SetCommMask,
  395.   GetCommModemStatus and any other low level comm functions }
  396. type
  397.   LPPort = ^TPort;
  398.      TPort = record
  399.           VarString: TVarString;
  400.           hComm: THandle;
  401.           szDeviceName: array [1..1] of Char;
  402.      end;
  403. var
  404.   TempPort: LPPort;
  405.   PortSize: LongInt;
  406.   FError: longint;
  407. begin
  408.   result := 0;
  409.      if not ALineIsOpen then exit; // use local copy
  410.      PortSize := sizeof(TPort);
  411.      GetMem(TempPort, PortSize);
  412.      TempPort^.VarString.dwTotalSize := PortSize;
  413.      try
  414.           repeat
  415.             FError := lineGetID(ALine, 0, ACall,
  416.               LINECALLSELECT_LINE,
  417.               lpVarString(TempPort), 'comm');
  418.               if FError < 0 then exit;
  419.               if (TempPort^.VarString.dwNeededSize >
  420.                  TempPort^.VarString.dwTotalSize)
  421.                  then begin
  422.                  PortSize := TempPort^.VarString.dwNeededSize;
  423.                  FreeMem(TempPort);
  424.                  GetMem(TempPort, PortSize);
  425.                  TempPort^.VarString.dwTotalSize := PortSize;
  426.                  FError := -1;
  427.                  end;
  428.           until FError = 0;
  429.           Result := TempPort^.hComm;
  430.   finally
  431.     FreeMem(TempPort);
  432.   end;
  433. end;
  434.  
  435. //-- End of Local Functions ----------------------------------------------------
  436.  
  437. // Is Line Open?
  438. function TkkamTAPI.CheckLineIsOpen: boolean;
  439. begin
  440.   Result := LineIsOpen;
  441. end;
  442.  
  443. // Phone number management
  444. function TkkamTAPI.ReadPhoneNumber :  string;
  445. begin
  446.   result := FPhoneNumber;
  447.   APhoneNumber := FPhoneNumber; // set local copy too
  448. end;
  449.  
  450. procedure TkkamTAPI.WritePhoneNumber(NewPhoneNumber : String);
  451. begin
  452.   FPhoneNumber := NewPhoneNumber;
  453.   APhoneNumber := NewPhoneNumber; // set local copy too
  454. end;
  455.  
  456. procedure TkkamTAPI.ChangePhoneNumber(NewPhoneNumber : string);
  457. begin
  458.   WritePhoneNumber(NewPhoneNumber);
  459. end;
  460.  
  461. // Line Management
  462.  
  463. function TkkamTAPI.OpenLine(AcceptCalls : boolean; var OpenMsg : string)
  464.                                          : boolean;
  465. var
  466.   OpenResult: longint;
  467. begin
  468.  Result := False;
  469.   if AcceptCalls then
  470.       // open a line (outgoing and incoming calls) and get the line handle
  471.   if AutoSelectLine then // automatically select the device
  472.      OpenResult := LineOpen(LineApp, LINEMAPPER, @ALine, FVersion, 0, 0,
  473.         LINECALLPRIVILEGE_OWNER, fMediaMode,
  474.            @FLineCallParams)
  475.   else
  476.      OpenResult := LineOpen(LineApp, FDev, @ALine, FVersion, 0, 0,
  477.         LINECALLPRIVILEGE_OWNER, fMediaMode, nil);
  478.      // open a line (outgoing calls only) and get the line handle
  479.   if AutoSelectLine then // automatically select the device
  480.      OpenResult := LineOpen(LineApp, LINEMAPPER, @ALine, FVersion, 0, 0,
  481.         LINECALLPRIVILEGE_NONE, fMediaMode,
  482.            @FLineCallParams)
  483.   else
  484.      OpenResult := LineOpen(LineApp, FDev, @ALine, FVersion, 0, 0,
  485.         LINECALLPRIVILEGE_NONE, fMediaMode, nil);
  486.   case OpenResult of
  487.      0: begin
  488.        Result := True; // success so drop through
  489.        OpenMsg := 'Line is Open';
  490.        ALineIsOpen := True;
  491.        AkkamTAPI.LineIsOpen := True;
  492.        // create thread suspended
  493.        TriggerCommThreadEvent(taResume);
  494.        end;
  495.      LINEERR_ALLOCATED: OpenMsg := 'LINEERR_ALLOCATED';
  496.      LINEERR_BADDEVICEID: OpenMsg := 'LINEERR_BADDEVICEID';
  497.      LINEERR_INCOMPATIBLEAPIVERSION: OpenMsg :=
  498.        'LINEERR_INCOMPATIBLEAPIVERSION';
  499.      LINEERR_INCOMPATIBLEEXTVERSION: OpenMsg :=
  500.        'LINEERR_INCOMPATIBLEEXTVERSION';
  501.      LINEERR_INVALAPPHANDLE: OpenMsg := 'LINEERR_INVALAPPHANDLE';
  502.      LINEERR_INVALMEDIAMODE: OpenMsg := 'LINEERR_INVALMEDIAMODE';
  503.      LINEERR_INVALPOINTER: OpenMsg := 'LINEERR_INVALPOINTER';
  504.      LINEERR_INVALPRIVSELECT: OpenMsg := 'LINEERR_INVALPRIVSELECT';
  505.      LINEERR_NODEVICE: OpenMsg := 'LINEERR_NODEVICE';
  506.      LINEERR_LINEMAPPERFAILED: OpenMsg := 'LINEERR_LINEMAPPERFAILED';
  507.      LINEERR_NODRIVER: OpenMsg := 'LINEERR_NODRIVER';
  508.      LINEERR_NOMEM: OpenMsg := 'LINEERR_NOMEM';
  509.      LINEERR_OPERATIONFAILED: OpenMsg := 'LINEERR_OPERATIONFAILED';
  510.      LINEERR_RESOURCEUNAVAIL: OpenMsg := 'LINEERR_RESOURCEUNAVAIL';
  511.      LINEERR_STRUCTURETOOSMALL: OpenMsg :=
  512.         'LINEERR_STRUCTURETOOSMALL';
  513.      LINEERR_UNINITIALIZED: OpenMsg := 'LINEERR_UNINITIALIZED';
  514.      LINEERR_REINIT: OpenMsg := 'LINEERR_REINIT';
  515.      LINEERR_OPERATIONUNAVAIL: OpenMsg := 'LINEERR_OPERATIONUNAVAIL';
  516.   else
  517.      OpenMsg := 'LineOpen returned an unknown value of ' + IntToStr(OpenResult);
  518.   end;
  519.   TriggerOpenLineEvent;
  520. end;  { OpenLine }
  521.  
  522. // TAPI Management
  523. function TkkamTAPI.TapiInitialize : Boolean;
  524. var
  525.   ErrNo: Longint;
  526.   S: string;
  527. begin
  528.   Result := false;
  529.   FCountryCode := 0;
  530.   FVersion := 0;
  531.   ErrNo := LineInitialize(@LineApp, MainInstance, LineCallback, '',
  532.   @LocalNumDevs);
  533.   case ErrNo of
  534.      0:  S := 'LineInitialize was successful';
  535.      LINEERR_INVALAPPNAME: S := 'Invalid Application Name';
  536.      LINEERR_OPERATIONFAILED: S := 'Line Init Operation Failed';
  537.      LINEERR_INIFILECORRUPT: S := 'INI File Corrupt';
  538.      LINEERR_RESOURCEUNAVAIL: S := 'Resource not available';
  539.      LINEERR_INVALPOINTER: S := 'Invalid Pointer';
  540.      LINEERR_REINIT: S := 'Not ready - trying again';
  541.      LINEERR_NODRIVER: S := 'Driver not found';
  542.      LINEERR_NODEVICE: S := 'Device not found';
  543.      LINEERR_NOMEM: S := 'Insufficient memory';
  544.      LINEERR_NOMULTIPLEINSTANCE: S := 'Can''t run multiple instances';
  545.   else
  546.      S := 'Unknown Reason (' + IntToStr(ErrNo) + ')';
  547.   end;
  548.   InitResults.Add(S);
  549.   // show how many devices available
  550.   InitResults.Add('Devices available: ' + IntToStr({FNumDevs}LocalNumDevs));
  551.  
  552.   if (ErrNo <> 0) then begin
  553.      InitResults.Add('LineInitialize failed with error: ' + S);
  554.      Exit;
  555.   end
  556.   else
  557.      ErrNo := LineNegotiateAPIVersion(LineApp, FDev, Ver, Ver,
  558.         @FVersion, @FExt);
  559.   if (ErrNo <> 0) then begin
  560.      case ErrNo of
  561.         LINEERR_BADDEVICEID: S := 'Bad Device ID';
  562.         LINEERR_NODRIVER: S := 'No Driver';
  563.         LINEERR_INCOMPATIBLEAPIVERSION: S := 'Incompatible Version';
  564.         LINEERR_OPERATIONFAILED: S := 'Operation failed';
  565.         LINEERR_INVALAPPHANDLE: S := 'Invalid Handle';
  566.         LINEERR_RESOURCEUNAVAIL: S := 'Resource Not Available';
  567.         LINEERR_INVALPOINTER: S := 'Invalid Pointer';
  568.         LINEERR_UNINITIALIZED: S := 'Line Not Initialized';
  569.         LINEERR_NOMEM: S := 'Insufficient Memory';
  570.         LINEERR_OPERATIONUNAVAIL: S := 'Operation Not Available Here';
  571.         LINEERR_NODEVICE: S := 'Device Not Found';
  572.      else
  573.         S := 'Unknown Reason (' + IntToStr(ErrNo) + ')';
  574.      end;
  575.      LineShutDown(LineApp);
  576.      InitResults.Add('LineNegotiateAPIVersion failed because:  ' + S);
  577.   end
  578.   else
  579.      Result := true;
  580.   TriggerTAPIInitEvent;
  581. end;  { TapiInitialize }
  582.  
  583. // Manage Devices
  584. procedure TkkamTAPI.EnumerateDevices;  { public }
  585. var
  586.   i, rc: integer;
  587.   AllocSize: Integer;
  588.   LineDevCaps: LPLINEDEVCAPS; // a pointer of TLineDevCaps type
  589. begin
  590.     // Added by Ken Kyler ---------
  591.   DeviceList.Clear;
  592.   // ---------
  593.   AllocSize := SizeOf(TLINEDEVCAPS);// + 512;
  594.   for i := 0 to {FNumDevs}LocalNumDevs - 1 do begin
  595.      LineDevCaps := AllocMem(AllocSize); // This will also fill with zeroes
  596.      try
  597.         // Get dev caps
  598.         LineDevCaps^.dwTotalSize := AllocSize;
  599.         rc := LineGetDevCaps(LineApp, i, FVersion, 0, LineDevCaps);
  600.         if (LineDevCaps^.dwNeededSize > LineDevCaps^.dwTotalSize) then begin
  601.            // Buffer too small; reallocate and try again
  602.            AllocSize := LineDevCaps^.dwNeededSize;
  603.            ReallocMem(LineDevCaps, AllocSize);
  604.            LineDevCaps^.dwTotalSize := AllocSize;
  605.            rc := LineGetDevCaps(LineApp, i, FVersion, 0, LineDevCaps);
  606.         end;
  607.         TapiCheck(rc);  // Raises exception if rc indicates a line error
  608.         // Extract line name
  609.         if (LineDevCaps^.dwStringFormat = STRINGFORMAT_ASCII) then
  610.           DeviceList.Add(RecordGetStr(LineDevCaps^,
  611.              @LineDevCaps^.dwLineNameSize))
  612.         else
  613.           DeviceList.Add('Invalid string format');
  614.      finally
  615.         FreeMem(LineDevCaps);
  616.      end;
  617.   end;
  618.   TriggerEnumerateDevicesEvent;
  619. end;  { EnumerateDevices }
  620.  
  621. // Call Manager Functions
  622. function TkkamTAPI.CreateCallManager : Boolean;
  623. var
  624.   S: string;
  625.   ErrNo: longint;
  626. begin
  627. result := False;
  628.   CreateManagerResults.Clear;
  629.   if not LineIsOpen then // if a line is open, no need to initialize TAPI
  630.      if not TapiInitialize then begin
  631.         CreateManagerResults.Add('Failed to initialize TAPI');
  632.         Exit;
  633.      end;
  634.  
  635.   { fill the LineCallParams structure.  Mandatory for data calls,
  636.     optional for voice calls }
  637.      with FLineCallParams do begin
  638.      dwTotalSize := sizeof(FLineCallParams);
  639.      dwBearerMode := LINEBEARERMODE_VOICE;
  640.      dwMediaMode := LINEMEDIAMODE_DATAMODEM; //LINEMEDIAMODE_INTERACTIVEVOICE
  641.   end;
  642.   if NOT LineIsOpen then
  643.     LineIsOpen := OpenLine(False, S);
  644.     AlineIsOpen := LineIsOpen;
  645.     CommStatusThread.Resume; // start thread
  646.   // now place the call
  647.   if FPulseDialing then
  648.   ErrNo := LineMakeCall(ALine, @ACall, PChar('p'+PhoneNumber), FCountryCode,
  649.      @FLineCallParams) else
  650.   ErrNo := LineMakeCall(ALine, @ACall, PChar(PhoneNumber), FCountryCode,
  651.      @FLineCallParams);
  652.   //ACall := FCall;  // make sure local copy is in sync
  653.   case ErrNo of
  654.      0: S := 'LineMakeCall succeeded'; // success
  655.      LINEERR_ADDRESSBLOCKED: S := 'LINEERR_ADDRESSBLOCKED';
  656.      LINEERR_BEARERMODEUNAVAIL: S := 'LINEERR_BEARERMODEUNAVAIL';
  657.      LINEERR_CALLUNAVAIL: S := 'LINEERR_CALLUNAVAIL';
  658.      LINEERR_DIALBILLING: S := 'LINEERR_DIALBILLING';
  659.      LINEERR_DIALDIALTONE: S := 'LINEERR_DIALDIALTONE';
  660.      LINEERR_DIALPROMPT: S := 'LINEERR_DIALPROMPT';
  661.      LINEERR_DIALQUIET: S := 'LINEERR_DIALQUIET';
  662.      LINEERR_INUSE: S := 'LINEERR_INUSE';
  663.      LINEERR_INVALADDRESS: S := 'LINEERR_INVALADDRESS';
  664.      LINEERR_INVALADDRESSID: S := 'LINEERR_INVALADDRESSID';
  665.      LINEERR_INVALADDRESSMODE: S := 'LINEERR_INVALADDRESSMODE';
  666.      LINEERR_INVALBEARERMODE: S := 'LINEERR_INVALBEARERMODE';
  667.      LINEERR_INVALCALLPARAMS: S := 'LINEERR_INVALCALLPARAMS';
  668.      LINEERR_INVALCOUNTRYCODE: S := 'LINEERR_INVALCOUNTRYCODE';
  669.      LINEERR_INVALLINEHANDLE: S := 'LINEERR_INVALLINEHANDLE';
  670.      LINEERR_INVALLINESTATE: S := 'LINEERR_INVALLINESTATE';
  671.      LINEERR_INVALMEDIAMODE: S := 'LINEERR_INVALMEDIAMODE';
  672.      LINEERR_INVALPARAM: S := 'LINEERR_INVALPARAM';
  673.      LINEERR_INVALPOINTER: S := 'LINEERR_INVALPOINTER';
  674.      LINEERR_INVALRATE: S := 'LINEERR_INVALRATE';
  675.      LINEERR_NOMEM: S := 'LINEERR_NOMEM';
  676.      LINEERR_OPERATIONFAILED: S := 'LINEERR_OPERATIONFAILED';
  677.      LINEERR_OPERATIONUNAVAIL: S := 'LINEERR_OPERATIONUNAVAIL';
  678.      LINEERR_RATEUNAVAIL: S := 'LINEERR_RATEUNAVAIL';
  679.      LINEERR_RESOURCEUNAVAIL: S := 'LINEERR_RESOURCEUNAVAIL';
  680.      LINEERR_STRUCTURETOOSMALL: S := 'LINEERR_STRUCTURETOOSMALL';
  681.      LINEERR_UNINITIALIZED: S := 'LINEERR_UNINITIALIZED';
  682.      LINEERR_USERUSERINFOTOOBIG: S := 'LINEERR_USERUSERINFOTOOBIG';
  683.   else
  684.      S := 'LineMakeCall returned an unknown value (' + IntToStr(ErrNo) + ')';
  685.   end;
  686.   //ALine := FLine;  // make sure local copy is in sync
  687.   CreateManagerResults.Add('LineMakeCall reports: ' + S);
  688.   TriggerCreateCallManagerEvent;  // Send CreateManagerResults to calling app.
  689. end; { CreateCallManager }
  690.  
  691. function TkkamTAPI.ShutdownManager: Boolean;
  692. var
  693.   ShutdownResults : string;
  694. begin
  695.   result := ShutdownCallManager(ShutdownResults);
  696. end;  { ShutdownManager }
  697.  
  698. // Dialing a Phone Number
  699. function TkkamTAPI.Dial : String;  { public }
  700. var
  701.   ErrNo: longint;
  702.   S: string;
  703. begin
  704.   if PhoneNumber='' then
  705.     begin
  706.       ShowMessage('You need to enter a phone number');
  707.       result := 'No Phone number entered';
  708.       exit;
  709.     end;
  710.  
  711.   result := 'Success';
  712.   if not AutoSelectLine and (Dev < 0) then begin // a device wasn't selected
  713.      result := 'You must first select a Line device!';
  714.      Exit;
  715.   end;
  716.   if AutoSelectLine then CreateCallManager
  717.   else
  718.   begin
  719.   ErrNo := TapiRequestMakeCall(
  720.      PChar(PhoneNumber), // the phone number
  721.      '', // application name, optional, could use PChar(Application.Title)
  722.      'Some person', // optional, this is the name of the person being called
  723.      ''); // optional comment
  724.   case ErrNo of
  725.      0: Exit; // success; exit with default message
  726.      TAPIERR_NOREQUESTRECIPIENT: S := 'TAPIERR_NOREQUESTRECIPIENT';
  727.      TAPIERR_INVALDESTADDRESS: S := 'TAPIERR_INVALDESTADDRESS';
  728.      TAPIERR_REQUESTQUEUEFULL: S := 'TAPIERR_REQUESTQUEUEFULL';
  729.      TAPIERR_INVALPOINTER: S := 'TAPIERR_INVALPOINTER';
  730.   else
  731.      S := 'unknown value (' + IntToStr(ErrNo) + ')';
  732.   end;
  733.      DialResults.Add('TapiRequestMakeCall returned: ' + S);
  734. end;
  735. TriggerDialEvent;
  736. end;  { Dial }
  737.  
  738. // Media Mode Management
  739. procedure TkkamTAPI.ChangeMediaMode(MediaModeSelected : Integer);  { public }
  740. begin
  741.   case MediaModeSelected of
  742.      0:  MediaMode := LINEMEDIAMODE_UNKNOWN;
  743.      1:  MediaMode := LINEMEDIAMODE_INTERACTIVEVOICE;
  744.      2:  MediaMode := LINEMEDIAMODE_AUTOMATEDVOICE;
  745.      3:  MediaMode := LINEMEDIAMODE_DATAMODEM;
  746.      4:  MediaMode := LINEMEDIAMODE_G3FAX;
  747.      5:  MediaMode := LINEMEDIAMODE_TDD;
  748.      6:  MediaMode := LINEMEDIAMODE_G4FAX;
  749.      7:  MediaMode := LINEMEDIAMODE_DIGITALDATA;
  750.      8:  MediaMode := LINEMEDIAMODE_TELETEX;
  751.      9:  MediaMode := LINEMEDIAMODE_VIDEOTEX;
  752.      10: MediaMode := LINEMEDIAMODE_TELEX;
  753.      11: MediaMode := LINEMEDIAMODE_MIXED;
  754.      12: MediaMode := LINEMEDIAMODE_ADSI;
  755.      13: MediaMode := LINEMEDIAMODE_VOICEVIEW;
  756.   else
  757.      MediaMode := LINEMEDIAMODE_INTERACTIVEVOICE; // safety valve
  758.   end;
  759.   FLineCallParams.dwMediaMode := MediaMode;
  760. end;  { ChangeMediaMode }
  761.  
  762. // Bearer Mode Management
  763. procedure TkkamTAPI.ChangeBearerMode(BearerModeSelected : Integer);  { public }
  764. begin
  765.   case BearerModeSelected of
  766.      0: FBearerMode := LINEBEARERMODE_VOICE;
  767.      1: FBearerMode := LINEBEARERMODE_SPEECH;
  768.      2: FBearerMode := LINEBEARERMODE_MULTIUSE;
  769.      3: FBearerMode := LINEBEARERMODE_DATA;
  770.      4: FBearerMode := LINEBEARERMODE_ALTSPEECHDATA;
  771.      5: FBearerMode := LINEBEARERMODE_NONCALLSIGNALING;
  772.      6: FBearerMode := LINEBEARERMODE_PASSTHROUGH;
  773.   else
  774.      FBearerMode := LINEBEARERMODE_SPEECH; // safety valve
  775.   end;
  776.   FLineCallParams.dwBearerMode := FBearerMode;
  777. end;  { ChangeBearerMode }
  778.  
  779. // Show TAPI Properties Dialog Box
  780. procedure TkkamTAPI.ShowLineTranslateDialog(APhoneNum : string;
  781.                                AHandle :  THandle);  { public }
  782. var
  783. TapiResult : word;
  784. TempNumber : string;
  785. begin
  786.   TempNumber := '+1' + Copy(APhoneNum, 2, Length(APhoneNum)-1);
  787.   if  FDev<0 then
  788.   TapiResult := lineTranslateDialogA(LineApp, 0, ver, AHandle,
  789.         LPCStr(TempNumber))
  790.   else
  791.   TapiResult := lineTranslateDialogA(LineApp, FDev, ver, AHandle,
  792.         LPCStr(TempNumber));
  793.   if TapiResult<>0 then
  794.     ShowMessage('Could not show Line Translate Dialog Box')
  795.   else
  796.    lineTranslateAddress(LineApp, FDev, ver, PChar(fPhoneNumber), 0,
  797.          FLineTranslateOptions, FlpTranslateOutput);
  798. end;  { ShowLineTranslateDialog }
  799.  
  800. { Event triggers: }
  801. procedure TkkamTAPI.TriggerCreateCallManagerEvent;
  802. { Triggers the OnCreateCallManager event. This is a virtual method
  803.   (descendants of this component can override it). }
  804. { CDK: Call as needed to trigger event. }
  805. begin
  806.   if assigned(FOnCreateCallManager) then
  807.     FOnCreateCallManager(Self, CreateManagerResults);
  808. end;  { TriggerCreateCallManagerEvent }
  809.  
  810. procedure TkkamTAPI.TriggerShutdownManagerEvent;
  811. { Triggers the OnShutdownManager event. This is a virtual method
  812.   (descendants of this component can override it). }
  813. { CDK: Call as needed to trigger event. }
  814. begin
  815.   if assigned(FOnShutdownManager) then
  816.     FOnShutdownManager(Self, ShutdownResults);
  817. end;  { TriggerShutdownManagerEvent }
  818.  
  819. procedure TkkamTAPI.TriggerDestroyCallManagerEvent;
  820. { Triggers the OnDestroyCallManager event. This is a virtual method (descendants of this
  821. component can override it). }
  822. { CDK: Call as needed to trigger event. }
  823. begin
  824.   if assigned(FOnDestroyCallManager) then
  825.     FOnDestroyCallManager(Self, ShutdownResults);
  826. end;  { TriggerDestroyCallManagerEvent }
  827.  
  828. procedure TkkamTAPI.TriggerEnumerateDevicesEvent;
  829. { Triggers the OnEnumerateDevices event. This is a virtual method (descendants of this component
  830. can override it). }
  831. { CDK: Call as needed to trigger event. }
  832. begin
  833.   if assigned(FOnEnumerateDevices) then
  834.     FOnEnumerateDevices(Self, DeviceList);
  835. end;  { TriggerEnumerateDevicesEvent }
  836.  
  837. procedure TkkamTAPI.TriggerTAPIInitEvent;
  838. { Triggers the OnTAPIInit event. This is a virtual method (descendants of this component can
  839. override it). }
  840. { CDK: Call as needed to trigger event. }
  841. begin
  842.   if assigned(FOnTAPIInit) then
  843.     FOnTAPIInit(Self);
  844. end;  { TriggerTAPIInitEvent }
  845.  
  846. procedure TkkamTAPI.TriggerOpenLineEvent;
  847. { Triggers the OnOpenLine event. This is a virtual method (descendants of this component can
  848. override it). }
  849. { CDK: Call as needed to trigger event. }
  850. begin
  851.   if assigned(FOnOpenLine) then
  852.     FOnOpenLine(Self, InitResults);
  853. end;  { TriggerOpenLineEvent }
  854.  
  855. procedure TkkamTAPI.TriggerDialEvent;
  856. { Triggers the OnDial event. This is a virtual method (descendants of this component can override
  857. it). }
  858. { CDK: Call as needed to trigger event. }
  859. begin
  860.   if assigned(FOnDial) then
  861.     FOnDial(Self, DialResults);
  862. end;  { TriggerDialEvent }
  863.  
  864. procedure TkkamTAPI.TriggerPhoneNumberChangeEvent;
  865. { Triggers the OnPhoneNumberChange event. This is a virtual method (descendants of this
  866. component can override it). }
  867. { CDK: Call as needed to trigger event. }
  868. begin
  869.   if assigned(FOnPhoneNumberChange) then
  870.     FOnPhoneNumberChange(Self);
  871. end;  { TriggerPhoneNumberChangeEvent }
  872.  
  873. procedure TkkamTAPI.TriggerChangeMediaModeEvent;
  874. { Triggers the OnChangeMediaMode event. This is a virtual method (descendants of this component
  875. can override it). }
  876. { CDK: Call as needed to trigger event. }
  877. begin
  878.   if assigned(FOnChangeMediaMode) then
  879.     FOnChangeMediaMode(Self);
  880. end;  { TriggerChangeMediaModeEvent }
  881.  
  882. procedure TkkamTAPI.TriggerChangeBearerModeEvent;
  883. { Triggers the OnChangeBearerMode event. This is a virtual method (descendants of this
  884. component can override it). }
  885. { CDK: Call as needed to trigger event. }
  886. begin
  887.   if assigned(FOnChangeBearerMode) then
  888.     FOnChangeBearerMode(Self);
  889. end;  { TriggerChangeBearerModeEvent }
  890. procedure TkkamTAPI.TriggerCommThreadEvent(ThreadAction : TThreadAction);
  891. begin
  892.   if assigned(FOnCommThreadEvent) then
  893.      FOnCommThreadEvent(Self, ThreadAction);
  894. end;   { TriggerCommThread }
  895.  
  896. procedure TkkamTAPI.TriggerCommEvent(Sender : TObject;
  897.               ACommEvent : TCommEvent; AStatus : integer);
  898. begin
  899.   if assigned(FOnTriggerCommEvent) then
  900.     FOnTriggerCommEvent(Sender, ACommEvent, AStatus);
  901. end;
  902.  
  903. destructor TkkamTAPI.Destroy;
  904. begin
  905.     InitResults.Free;
  906.     DeviceList.Free;
  907.     ShutdownResults.Free;;
  908.     CreateManagerResults.Free;;
  909.     DialResults.Free;
  910.     CommStatusThread.Free;
  911.     CommStatusThread := Nil;
  912.    // TapiResults.Free;
  913.   { CDK: Free allocated memory and created objects here. }
  914.   inherited Destroy;
  915. end;  { Destroy }
  916.  
  917. constructor TkkamTAPI.Create(AOwner: TComponent);
  918. { Creates an object of type TkkamTAPI, and initializes properties. }
  919. var
  920.   LineOpenResult : longint;
  921. begin
  922.   inherited Create(AOwner);
  923.   { Initialize properties with default values: }
  924.   FAutoSelectLine := true;
  925.   FPhoneNumber := '';
  926.   InitResults := TStringList.Create;
  927.   DeviceList:= TStringList.Create;
  928.   ShutdownResults:= TStringList.Create;
  929.   CreateManagerResults := TStringList.Create;
  930.   DialResults := TStringList.Create;
  931.   TapiMessages := TStringList.Create;
  932.   TAPI_Initialized := True;
  933.   fMediaMode  := LINEMEDIAMODE_DATAMODEM;
  934.   fBearerMode := LINEBEARERMODE_VOICE; // changed from speech
  935.   fDev := 0; // default device
  936.   if not TapiInitialize
  937.      then TAPI_Initialized := False
  938.   else
  939.     begin
  940.       TAPI_Initialized := true;
  941.       with FLineCallParams do begin
  942.         dwTotalSize := sizeof(FLineCallParams);
  943.         dwBearerMode := fBearerMode;;
  944.         dwMediaMode := fMediaMode;
  945.       end;
  946.     end;
  947.     EnumerateDevices; // fill the combobox with the available devices
  948.   // Open line to get valid Port Handle : June 27, 1998
  949.   LineOpenResult := LineOpen(LineApp, FDev, @ALine, FVersion, 0, 0,
  950.         LINECALLPRIVILEGE_NONE, fMediaMode, nil);
  951.   if LineOpenResult=0  then
  952.     begin
  953.       LineIsOpen := true; // initial value
  954.       ALineIsOpen := True;
  955.      {   }
  956.        // next line moved here to get valid FPort value
  957.        FPort := GetPortHandle; // added 18 Jan 98
  958.        // create thread suspended
  959.        CommStatusThread := TCommStatus.Init(Self, true, FPort);
  960.     end
  961.   else
  962.     begin
  963.       LineIsOpen := false; // initial value
  964.       ALineIsOpen := false;
  965.     end;
  966.     AKkamTAPI := Self;
  967.     AkkamTAPI.LineIsOpen := True;
  968. end;  { Create }
  969.  
  970. { TCommStatus }
  971.  
  972. constructor TCommStatus.Init(Owner : TComponent;
  973.                              Suspended : Boolean; PortRead : THandle);
  974. begin
  975.   inherited Create(Suspended);
  976.   TheOwner := Owner;
  977.   SetPort(PortRead);
  978. end;
  979.  
  980. procedure TCommStatus.TriggerTapiCommEvent(Sender : TObject;
  981.                           CommEvent : TCommEvent; Status : integer);
  982. begin
  983.   TkkamTAPI(TheOwner).TriggerCommEvent(Sender, CommEvent, Status);
  984. end;
  985.  
  986. procedure TCommStatus.Execute;
  987. var
  988.   dwEvent: DWord;
  989.   dwStatus: DWord;
  990. begin
  991.   dwEvent := 0;
  992.   SetCommMask(ThePort, EV_DSR or EV_CTS or SETDTR);
  993.   repeat
  994.      WaitCommEvent(THandle(ThePort), dwEvent, nil);
  995.      GetCommModemStatus(THandle(ThePort), dwStatus);
  996.      case dwEvent of                            
  997.         EV_DSR:  TriggerTapiCommEvent(Self, tceDSR, green);
  998.           // TapiCallManager.SetBitmap(TapiCallManager.DSR, green);
  999.         SETDTR:  TriggerTapiCommEvent(Self, tceDTR, green);
  1000.           //TapiCallManager.SetBitmap(TapiCallManager.DTR, green);
  1001.         EV_CTS:  TriggerTapiCommEvent(Self, tceCTS, green);
  1002.           //TapiCallManager.SetBitmap(TapiCallManager.CTS, green);
  1003.      end;
  1004.    until Terminated;
  1005. end;
  1006.  
  1007. procedure TCommStatus.SetPort(Value : THandle);
  1008. begin
  1009.   ThePort := Value;
  1010. end;
  1011.  
  1012. function TCommStatus.GetPort : THandle;
  1013. begin
  1014.   result := ThePort;
  1015. end;
  1016.  
  1017. procedure Register;
  1018. begin
  1019.   RegisterComponents('Tapi', [TkkamTAPI]);
  1020.   { CDK: If you want to register your non-visual component without it appearing on the palette,use
  1021. RegisterNoIcon in place of RegisterComponents:
  1022.   RegisterNoIcon([TkkamTAPI]); }
  1023. end;  { Register }
  1024.  
  1025. end.
  1026.